package com.pavlinic.mylisp.specialForms;


import com.pavlinic.mylisp.EvaluationContext;
import com.pavlinic.mylisp.Expression;
import com.pavlinic.mylisp.Function;
import com.pavlinic.mylisp.ListExpression;
import com.pavlinic.mylisp.ValueExpression;

public enum SpecialForm {
  QUOTE("quote") {
    @Override
    Expression evaluate(ListExpression listExpression, EvaluationContext context) {
      return listExpression.get(1);
    }
  },
  DOT(".") {
    @Override
    Expression evaluate(ListExpression listExpression, EvaluationContext context) {
      return Dot.evaluateDot(listExpression, context);
    }
  }, DEF("def") {

    @Override
    Expression evaluate(ListExpression listExpression, EvaluationContext context) {
      return Def.evaluateDef(listExpression, context);
    }
    
  }, 
  //has no use until dot can invoke methods on objects :(
  NEW("new") {
    @Override
    Expression evaluate(ListExpression listExpression, EvaluationContext context) {
      return New.evaluateNew(listExpression);
    }
  }, LAMBDA("lambda") {
    @Override
    Expression evaluate(ListExpression listExpression, EvaluationContext context) {
      return new Function((ListExpression) listExpression.get(1), listExpression.get(2));
    }
    
  }, IF("if") {
	@Override
	public Expression evaluate(ListExpression listExpression, EvaluationContext context) {
		return If.evaluateIf(listExpression, context);
	}
  }, 
  //This allows us to pass an Expression structure to . as a value that can be manipulated
  //in java
  EXPR("expr") {
	@Override
	public Expression evaluate(ListExpression listExpression, EvaluationContext context) {
		final Expression evaluated = listExpression.get(1).evaluate(context);
		return evaluated == null ? null : new ValueExpression(evaluated);
	}
};
  private String name;
  
  SpecialForm(String name) {
    this.name = name;
  }
  
  abstract Expression evaluate(ListExpression listExpression, EvaluationContext context);

  public static boolean isSpecialForm(String functionName) {
    return find(functionName) != null;
  }

  private static SpecialForm find(String functionName) {
    for (SpecialForm form : values()) {
      if (form.getName().equals(functionName)) {
        return form;
      }
    }
    return null;
  }

  private String getName() {
    return name;
  }

  public static Expression evaluate(String functionName, ListExpression listExpression, EvaluationContext context) {
    return find(functionName).evaluate(listExpression, context);
  }


}
